using Universal.Application.Contracts.Common;
using Universal.Application.Contracts.Dto.Menu;
using Universal.Application.Repositories;
using Universal.Domain.Entities.App;
using Universal.Domain.Repositories;
using Microsoft.EntityFrameworkCore;

namespace Universal.Application.Services;

/// <summary>
/// 菜单服务
/// </summary>
public class MenuService : IMenuService
{
    private readonly IRepository<AppMenu> _menuRepository;
    private readonly IRepository<AppUser> _userRepository;
    private readonly IRepository<AppRole> _roleRepository;

    public MenuService(IRepository<AppMenu> menuRepository, IRepository<AppUser> userRepository, IRepository<AppRole> roleRepository)
    {
        _menuRepository = menuRepository;
        _userRepository = userRepository;
        _roleRepository = roleRepository;
    }

    /// <summary>
    /// 根据用户ID获取用户菜单
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns>用户可访问的菜单列表</returns>
    public async Task<dynamic> GetUserMenusByUserIdAsync(Guid userId)
    {
        try
        {
            // 1. 使用通用仓储接口，通过导航属性获取用户及其角色
            var user = await _userRepository.Query()
                .Include(u => u.Roles)
                .ThenInclude(r => r.Menus) // 通过导航属性获取角色关联的菜单
                .FirstOrDefaultAsync(u => u.Id == userId);

            if (user == null)
            {
                return ApiResponse<string>.Failure(404, "用户不存在");
            }

            // 2. 通过导航属性获取用户所有角色关联的菜单
            var userMenus = new HashSet<AppMenu>(); // 使用HashSet去重

            foreach (var role in user.Roles.Where(r => r.IsActive))
            {
                foreach (var menu in role.Menus.Where(m => m.IsActive))
                {
                    userMenus.Add(menu);
                }
            }

            // 3. 获取所有菜单，包括父菜单和子菜单
            var allMenus = await _menuRepository.Query()
                .Where(m => m.IsActive)
                .ToListAsync();

            // 4. 递归获取父菜单，确保显示完整的菜单层级
            var allAccessibleMenus = new HashSet<AppMenu>();
            foreach (var menu in userMenus)
            {
                allAccessibleMenus.Add(menu);
                // 递归添加父菜单
                AddParentMenus(menu, allMenus, allAccessibleMenus);
            }

            // 5. 转换为DTO并构建菜单树
            var menuDtos = allAccessibleMenus.Select(m => new MenuDto
            {
                Id = m.Id,
                Menuname = m.Menuname,
                Path = m.Path,
                Icon = m.Icon,
                Sort = m.Sort,
                ParentId = m.ParentId,
                IsActive = m.IsActive
            }).ToList();

            var tree = BuildMenuTree(menuDtos, null);
            return ApiResponse<List<MenuDto>>.Success(tree);
        }
        catch (Exception ex)
        {
            return ApiResponse<string>.Failure(500, $"获取用户菜单失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 递归添加父菜单
    /// </summary>
    /// <param name="menu">当前菜单</param>
    /// <param name="allMenus">所有菜单</param>
    /// <param name="accessibleMenus">可访问的菜单集合</param>
    private void AddParentMenus(AppMenu menu, List<AppMenu> allMenus, HashSet<AppMenu> accessibleMenus)
    {
        if (menu.ParentId.HasValue)
        {
            var parentMenu = allMenus.FirstOrDefault(m => m.Id == menu.ParentId.Value);
            if (parentMenu != null && parentMenu.IsActive)
            {
                accessibleMenus.Add(parentMenu);
                // 递归添加父菜单的父菜单
                AddParentMenus(parentMenu, allMenus, accessibleMenus);
            }
        }
    }

    /// <summary>
    /// 获取当前用户的菜单
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns>用户可访问的菜单列表</returns>
    public async Task<dynamic> GetCurrentUserMenusAsync(Guid userId)
    {
        try
        {
            // 获取用户及其角色
            var user = await _userRepository.Query()
                .Include(u => u.Roles)
                .ThenInclude(r => r.Menus)
                .FirstOrDefaultAsync(u => u.Id == userId);

            if (user == null)
            {
                return ApiResponse<string>.Failure(404, "用户不存在");
            }

            // 获取用户所有角色关联的菜单
            var userMenus = new HashSet<AppMenu>();

            // 遍历用户的所有角色
            foreach (var role in user.Roles.Where(r => r.IsActive))
            {
                // 遍历角色关联的所有菜单
                foreach (var menu in role.Menus.Where(m => m.IsActive))
                {
                    userMenus.Add(menu);
                }
            }

            // 如果没有找到任何菜单，返回空列表
            if (!userMenus.Any())
            {
                return ApiResponse<List<MenuDto>>.Success(new List<MenuDto>());
            }

            // 转换为DTO并构建菜单树
            var menuDtos = userMenus.Select(m => new MenuDto
            {
                Id = m.Id,
                Menuname = m.Menuname,
                Path = m.Path,
                Icon = m.Icon,
                Sort = m.Sort,
                ParentId = m.ParentId,
                IsActive = m.IsActive
            }).ToList();

            var tree = BuildMenuTree(menuDtos, null);
            return ApiResponse<List<MenuDto>>.Success(tree);
        }
        catch (Exception ex)
        {
            return ApiResponse<string>.Failure(500, $"获取用户菜单失败: {ex.Message}");
        }
    }

    // 获取菜单树
    public async Task<dynamic> GetMenuTreeAsync()
    {
        var menus = await _menuRepository.GetAllAsync();
        var menuDtos = menus.Select(m => new MenuDto
        {
            Id = m.Id,
            Menuname = m.Menuname,
            Path = m.Path,
            Icon = m.Icon,
            Sort = m.Sort,
            ParentId = m.ParentId,
            IsActive = m.IsActive
        }).ToList();

        var tree = BuildMenuTree(menuDtos, null);
        return ApiResponse<List<MenuDto>>.Success(tree);
    }

    // 新增或编辑菜单
    public async Task<dynamic> AddOrUpdateMenuAsync(MenuDto dto)
    {
        var allMenus = await _menuRepository.GetAllAsync();

        if (dto.Id == Guid.Empty)
        {
            // 新增时全表唯一
            if (allMenus.Any(m => m.Menuname == dto.Menuname))
            {
                return ApiResponse<string>.Failure(400, "菜单名称已存在，不能重复");
            }

            if (allMenus.Any(m => m.Path == dto.Path))
            {
                return ApiResponse<string>.Failure(400, "菜单路径已存在，不能重复");
            }

            // 新增
            var menu = new AppMenu
            {
                Id = Guid.NewGuid(),
                Menuname = dto.Menuname,
                Path = dto.Path,
                Icon = dto.Icon,
                Sort = dto.Sort,
                ParentId = dto.ParentId,
                IsActive = dto.IsActive
            };
            await _menuRepository.AddAsync(menu);
            return ApiResponse<string>.Success("菜单新增成功");
        }
        else
        {
            // 编辑时要排除自己
            if (allMenus.Any(m => m.Menuname == dto.Menuname && m.Id != dto.Id))
            {
                return ApiResponse<string>.Failure(400, "菜单名称已存在，不能重复");
            }

            if (allMenus.Any(m => m.Path == dto.Path && m.Id != dto.Id))
            {
                return ApiResponse<string>.Failure(400, "菜单路径已存在，不能重复");
            }

            var menu = await _menuRepository.GetByIdAsync(dto.Id);
            if (menu == null)
            {
                return ApiResponse<string>.Failure(404, "菜单不存在");
            }

            menu.Menuname = dto.Menuname;
            menu.Path = dto.Path;
            menu.Icon = dto.Icon;
            menu.Sort = dto.Sort;
            menu.ParentId = dto.ParentId;
            menu.IsActive = dto.IsActive;
            await _menuRepository.UpdateAsync(menu);
            return ApiResponse<string>.Success("菜单编辑成功");
        }
    }

    // 删除菜单（递归删除子菜单）
    public async Task<dynamic> DeleteMenuAsync(Guid menuId)
    {

        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null)
            return ApiResponse<string>.Failure(5001, "菜单不存在");

        // 判断是否有子级菜单
        var allMenus = await _menuRepository.GetAllAsync();
        var hasChildren = allMenus.Any(m => m.ParentId == menuId);
        if (hasChildren)
            return ApiResponse<string>.Failure(5002, "请先删除子级菜单");

        await _menuRepository.DeleteAsync(menu);
        return ApiResponse<string>.Success("菜单删除成功");
    }

    private async Task DeleteMenuRecursive(Guid menuId, List<AppMenu> allMenus)
    {
        var children = allMenus.Where(m => m.ParentId == menuId).ToList();
        foreach (var child in children)
        {
            await DeleteMenuRecursive(child.Id, allMenus);
        }
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu != null)
        {
            await _menuRepository.DeleteAsync(menu);
        }
    }

    // 恢复默认菜单
    public async Task<dynamic> RestoreDefaultMenusAsync()
    {
        // 1. 递归删除所有菜单（从根节点开始）
        var allMenus = await _menuRepository.GetAllAsync();
        var rootMenus = allMenus.Where(m => m.ParentId == null).ToList();
        foreach (var root in rootMenus)
        {
            await DeleteMenuRecursive(root.Id, allMenus.ToList());
        }

        // 2. 插入默认菜单
        var defaultMenus = GetDefaultMenus();
        foreach (var menu in defaultMenus)
        {
            await AddMenuRecursive(menu, null);
        }
        return ApiResponse<string>.Success("默认菜单已恢复");
    }

    private async Task<dynamic> AddMenuRecursive(MenuDto dto, Guid? parentId)
    {
        var menu = new AppMenu
        {
            Id = Guid.NewGuid(),
            Menuname = dto.Menuname,
            Path = dto.Path,
            Icon = dto.Icon,
            Sort = dto.Sort,
            ParentId = parentId
        };
        await _menuRepository.AddAsync(menu);
        foreach (var child in dto.Children)
        {
            await AddMenuRecursive(child, menu.Id);
        }
        return ApiResponse<string>.Success("菜单新增成功");
    }

    private List<MenuDto> BuildMenuTree(List<MenuDto> menus, Guid? parentId)
    {
        return menus
            .Where(m => m.ParentId == parentId)
            .OrderBy(m => m.Sort)
            .Select(m => new MenuDto
            {
                Id = m.Id,
                Menuname = m.Menuname,
                Path = m.Path,
                Icon = m.Icon,
                Sort = m.Sort,
                ParentId = m.ParentId,
                IsActive = m.IsActive,
                Children = BuildMenuTree(menus, m.Id)
            }).ToList();
    }

    // 默认菜单，完全参照 MenuList.vue
    private List<MenuDto> GetDefaultMenus()
    {
        return new List<MenuDto>
        {
            new MenuDto
            {
                Menuname = "Dashboard",
                Path = "/dashboard/dashboardview",
                Icon = "Monitor",
                Sort = 1,
                IsActive = true
            },
            new MenuDto
            {
                Menuname = "系统管理",
                Path = "/system",
                Icon = "Setting",
                Sort = 2,
                Children = new List<MenuDto>
                {
                    new MenuDto { Menuname = "用户管理", Path = "/system/user/userlist", Icon = "User", Sort = 1 },
                    new MenuDto { Menuname = "角色管理", Path = "/system/role/rolelist", Icon = "User", Sort = 2 },
                    new MenuDto { Menuname = "菜单管理", Path = "/system/menu/menulist", Icon = "Edit", Sort = 3 },
                    new MenuDto { Menuname = "权限管理", Path = "/system/permission/permissionlist", Icon = "Edit", Sort = 4 },
                },
                IsActive = true
            },
            new MenuDto
            {
                Menuname = "日志管理",
                Path = "/log/loglist",
                Icon = "Document",
                Sort = 3,
                IsActive = true
            },
            new MenuDto
            {
                Menuname = "系统设置",
                Path = "/setupsystem",
                Icon = "Tools",
                Sort = 4,
                IsActive = true
            },
            new MenuDto
            {
                Menuname = "文章管理",
                Path = "/content",
                Icon = "Edit",
                Sort = 5,
                IsActive = true,
                Children = new List<MenuDto>
                {
                    new MenuDto { Menuname = "文章列表", Path = "/content/articlelist", Icon = "Document", Sort = 1 },
                    new MenuDto { Menuname = "新增/编辑", Path = "/content/articleadd", Icon = "Edit", Sort = 2 }
                }
            },
            new MenuDto
            {
                Menuname = "文件管理",
                Path = "/file",
                Icon = "Folder",
                Sort = 6,
                Children = new List<MenuDto>
                {
                    new MenuDto { Menuname = "文件列表", Path = "/file/filelist", Icon = "Folder", Sort = 1 },
                    new MenuDto { Menuname = "文件上传", Path = "/file/fileupload", Icon = "Folder", Sort = 2 }
                },
                IsActive = true
            },
            new MenuDto
            {
                Menuname = "个人中心",
                Path = "/profile/profileview",
                Icon = "Avatar",
                Sort = 7,
                IsActive = true
            }
        };
    }

    public async Task<dynamic> EnableMenuAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null)
        {
            return ApiResponse<string>.Failure(404, "菜单不存在");
        }
        if (menu.IsActive)
        {
            return ApiResponse<string>.Failure(400, "菜单已启用,无需重复操作");
        }
        menu.IsActive = true;
        await _menuRepository.UpdateAsync(menu);
        return ApiResponse<string>.Success("菜单启用成功");
    }

    public async Task<dynamic> DisableMenuAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null)
        {
            return ApiResponse<string>.Failure(404, "菜单不存在");
        }
        if (!menu.IsActive)
        {
            return ApiResponse<string>.Failure(400, "菜单已禁用,无需重复操作");
        }
        menu.IsActive = false;
        await _menuRepository.UpdateAsync(menu);
        return ApiResponse<string>.Success("菜单禁用成功");
    }
}